﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Formats.Biff.OfficeArt;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
#if DEBUG
    internal delegate void Action<T, T2>(T t, T2 t2);
    internal delegate void MyAction<A, B>(ref A a, B b);
    public class ReadWriteChecker
    {
        static Dictionary<Type,bool> dic = new Dictionary<Type, bool>();
        public static bool disabled = false;

        internal static void CheckStruct<T>
            (MyAction<T, BinaryReader> readAction, MyAction<T, BinaryWriter> writeAction, BinaryReader reader, ref T t) where T: struct
        {
            if (disabled)
                return;
            if (dic.ContainsKey(typeof (T)) && dic[typeof (T)])
                return;
            dic.Add(typeof (T), true);
            var position = reader.BaseStream.Position;
            readAction(ref t, reader);
            var endPosition = reader.BaseStream.Position;
            int byteCount = (int) (endPosition - position);
            reader.BaseStream.Position = position;
            byte[] readBytes = reader.ReadBytes(byteCount);
            reader.BaseStream.Position = position;
            byte [] writtenBytes = new byte[readBytes.Length];
            MemoryStream ms = new MemoryStream(writtenBytes);
            BinaryWriter writer = new BinaryWriter(ms);
            writeAction(ref t, writer);
            Contract.Assert(writer.BaseStream.Position == readBytes.Length);
            writer.Flush();
            for (int i = 0; i < readBytes.Length; i++)
                Contract.Assert(readBytes[i] == writtenBytes[i]);
            dic.Remove(typeof (T));
        }
        internal static void CheckClass<T>
            (Action<T, BinaryReader> readAction, Action<T, BinaryWriter> writeAction, BinaryReader reader, T t) where T: class
        {
            if (disabled)
                return;
            if (dic.ContainsKey(typeof(T)) && dic[typeof(T)])
                return;
            dic.Add(typeof(T), true);
            var position = reader.BaseStream.Position;
            readAction(t, reader);
            var endPosition = reader.BaseStream.Position;
            int byteCount = (int)(endPosition - position);
            reader.BaseStream.Position = position;
            byte[] readBytes = reader.ReadBytes(byteCount);
            reader.BaseStream.Position = position;
            byte[] writtenBytes = new byte[readBytes.Length + 8]; // 8 for the office art record header
            MemoryStream ms = new MemoryStream(writtenBytes);
            BinaryWriter writer = new BinaryWriter(ms);
            writeAction(t, writer);
            Contract.Assert(writer.BaseStream.Position == readBytes.Length);
            writer.Flush();
            Contract.Assert(readBytes.Length == writtenBytes.Length - 8);
            for (int i = 0; i < readBytes.Length; i++)
                Contract.Assert(readBytes[i] == writtenBytes[i]);
            dic.Remove(typeof(T));
        }
        internal static void CheckOfficeArtClass<T>
            (Action<T, OfficeArtReadContext> readAction, Action<T, OfficeArtWriteContext> writeAction, OfficeArtReadContext context, T t) where T : class
        {
            if (disabled)
                return;
            if (dic.ContainsKey(typeof(T)) && dic[typeof(T)])
                return;
            dic.Add(typeof(T), true);
            var position = context.BaseStream.Position;
            readAction(t, context);
            var endPosition = context.BaseStream.Position;
            int byteCount = (int)(endPosition - position);
            context.BaseStream.Position = position;
            byte[] readBytes = context.Reader.ReadBytes(byteCount);
            context.BaseStream.Position = position;
            byte[] writtenBytes = new byte[readBytes.Length + 8]; // 8 for the office art record header
            MemoryStream ms = new MemoryStream(writtenBytes);
            OfficeArtWriteContext writer = new OfficeArtWriteContext(new BinaryWriter(ms), null);
            writeAction(t, writer);
            Contract.Assert(writer.BaseStream.Position == readBytes.Length);
            writer.Writer.Flush();
            Contract.Assert(readBytes.Length == writtenBytes.Length - 8);
            for (int i = 0; i < readBytes.Length; i++)
                Contract.Assert(readBytes[i] == writtenBytes[i]);
            dic.Remove(typeof(T));
        }

    }
#endif
}